"""
参数设置界面
"""
import time
import tkinter as tk
from tkinter import font, filedialog, messagebox
from tkinter import ttk

from joystick_controller import JoystickController
from monkey_decode import MonkeyDecoder
from pump import WaterPumpController
from serial_data_process import SerialPacketProcessor
from training_rebuilt_up_down import CursorControl

frequency_cmd = [0x55, 0xaa, 0x00, 0x00, 0x0c, 0x02, 0x02, 0x03, 0xe8, 0x00, 0x00, 0x00,
                 0x00, 0x00, 0x00, 0x00, 0x00, 0xE7, 0xf0]  # 采样率1kHz
frequency_cmd_500 = [0x55, 0xaa, 0x00, 0x06, 0x0c, 0x02, 0x02, 0x01, 0xf4, 0x00, 0x00, 0x00,
                     0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xf0]  # 采样率500Hz
channel_cmd = [0x55, 0xaa, 0x00, 0x00, 0x0c, 0x02, 0x01, 0x00, 0x00, 0xff, 0xff, 0xff,
               0xff, 0xff, 0xff, 0xff, 0xff, 0x0F, 0xf0]  # 64通道
channel_cmd_60 = [0x55, 0xAA, 0x00, 0x06, 0x0C, 0x02, 0x01, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
                  0x7D, 0xDF, 0x7F, 0xFF, 0xFF, 0x2B, 0xF0]  # 60通道
start_cmd = [0x55, 0xaa, 0x00, 0x00, 0x0c, 0x02, 0x00, 0xaa, 0x00, 0x00, 0x00, 0x00,
             0x00, 0x00, 0x00, 0x00, 0x00, 0xA4, 0xf0]  # 开始采集
end_cmd = [0x55, 0xaa, 0x00, 0x00, 0x0c, 0x02, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00,
           0x00, 0x00, 0x00, 0x00, 0x00, 0xB5, 0xf0]  # 停止采集


class SettingsWindow:
    def __init__(self, master, serial_process):
        self.master = master
        self.score_threshold = 0.5  # 默认阈值
        self.model_path = r'./model/lda_model_0811.pkl'
        self.decoder = None
        self.cursor_control = None
        self.processor = None
        self.pump_controller = None

        self.win_size = 256
        self.step = 64
        self.channel_num = 60
        self.fs = 500
        self.status = True  # 设备状态
        self.trial_num = 0  # 试验总次数
        self.success_num = 0  # 试验成功次数
        self.window = None
        self.start_time = time.strftime("%Y-%m-%d %H:%M:%S")
        self.serial_process = serial_process
        self._create_window()
        # 启动运行时长更新
        self.update_running_time()
        self.refresh_ports()

    def _create_window(self):
        """创建参数输入窗口"""
        self.window = tk.Toplevel(self.master)
        self.window.title("参数设置")
        self.window.geometry("700x600")
        self.window.transient(self.master)  # 设为主窗口子窗口
        self.window.grab_set()  # 模态窗口（阻塞主窗口操作）

        # 统一字体
        common_font = font.Font(family='Arial', size=10)

        # 程序时间相关
        frame_time = tk.Frame(self.window)
        frame_time.pack(pady=10, fill=tk.X, padx=10)

        # 程序开始时间（显示文本框）
        tk.Label(frame_time, text="程序开始运行时间：").grid(row=0, column=0, padx=5, sticky=tk.W)
        self.lbl_start_time = tk.Label(frame_time, text=self.start_time, width=20)
        self.lbl_start_time.grid(row=0, column=1, padx=5, sticky=tk.W)

        # 程序已运行时长（显示文本框）
        tk.Label(frame_time, text="程序已运行时长：").grid(row=0, column=2, padx=5, sticky=tk.W)
        self.lbl_running_time = tk.Label(frame_time, text="00:00:00", width=15)
        self.lbl_running_time.grid(row=0, column=3, padx=5, sticky=tk.W)
        # 状态相关
        frame_status = tk.Frame(self.window, bd=2, relief=tk.GROOVE)
        frame_status.pack(pady=10, fill=tk.X, padx=10)
        tk.Label(frame_status, text="状态显示：", font=("Arial", 10, "bold")).grid(row=0, column=0, columnspan=4,
                                                                                  sticky=tk.W, padx=5, pady=5)
        # 设备状态（显示文本框）
        tk.Label(frame_status, text="设备状态：").grid(row=1, column=0, padx=5, pady=5, sticky=tk.W)
        self.device_status_var = tk.StringVar(value="正常")
        self.device_status = tk.Label(frame_status, textvariable=self.device_status_var)
        self.device_status.grid(row=1, column=1, padx=5, pady=5, sticky=tk.W)

        # 实验结果（显示文本框）
        self.trial_result_var = tk.StringVar(value="5/10")
        tk.Label(frame_status, text="试验结果：").grid(row=1, column=2, padx=10, pady=5, sticky=tk.W)
        self.trial_result = tk.Label(frame_status, textvariable=self.trial_result_var)
        self.trial_result.grid(row=1, column=3, padx=5, pady=5, sticky=tk.W)

        # 串口配置
        frame_serial = tk.Frame(self.window, bd=2, relief=tk.GROOVE)
        frame_serial.pack(fill=tk.X, padx=10, pady=10)

        tk.Label(frame_serial, text="串口配置：", font=("Arial", 10, "bold")).grid(row=0, column=0, columnspan=4,
                                                                                  sticky=tk.W, padx=5, pady=5)

        tk.Label(frame_serial, text="数据读取串口选择：").grid(row=1, column=0, padx=5, pady=5, sticky=tk.W)
        self.combo_data = ttk.Combobox(frame_serial, width=15)
        self.combo_data.grid(row=1, column=1, padx=5, pady=5, sticky=tk.W)
        self.btn_send_data = tk.Button(frame_serial, text="连接", command=self._conncet_data_combo)
        self.btn_send_data.grid(row=1, column=2, padx=5, pady=5, sticky=tk.W)

        tk.Label(frame_serial, text="喂水串口选择：").grid(row=2, column=0, padx=5, pady=5, sticky=tk.W)
        self.combo_water = ttk.Combobox(frame_serial, width=15)
        self.combo_water.grid(row=2, column=1, padx=5, pady=5, sticky=tk.W)

        self.btn_send_water = tk.Button(frame_serial, text="连接", command=self._connect_water_combo)
        self.btn_send_water.grid(row=2, column=2, padx=5, pady=5, sticky=tk.W)

        self.btn_refresh = tk.Button(frame_serial, text="刷新串口", command=self.refresh_ports)
        self.btn_refresh.grid(row=1, column=4, rowspan=2, padx=5, pady=5, sticky=tk.W)

        # 解码模型相关（已设置为左对齐）
        frame_model = tk.Frame(self.window, bd=2, relief=tk.GROOVE)
        frame_model.pack(fill=tk.X, padx=10, pady=10)

        tk.Label(frame_model, text="解码模型配置：", font=("Arial", 10, "bold")).grid(row=0, column=0, columnspan=3,
                                                                                     sticky=tk.W, padx=5, pady=5)

        # 解码模型选择行
        tk.Label(frame_model, text="解码模型：").grid(row=1, column=0, padx=5, pady=5, sticky=tk.W)

        # 模型路径显示（使用标签模拟文本框样式）
        self.model_path_var = tk.StringVar(value=self.model_path)
        tk.Label(frame_model, textvariable=self.model_path_var).grid(row=1, column=1, padx=5, pady=5,
                                                                     sticky=tk.W)
        self.btn_select_model = tk.Button(frame_model, text="选择模型", command=self._choose_model)
        self.btn_select_model.grid(row=1, column=2, padx=5, pady=5, sticky=tk.W)
        self.btn_load_model = tk.Button(frame_model, text="加载模型", command=self._load_model)
        self.btn_load_model.grid(row=1, column=3, padx=5, pady=5, sticky=tk.W)

        # Score设置行
        tk.Label(frame_model, text="score设置：").grid(row=2, column=0, padx=5, pady=5, sticky=tk.W)
        self.entry_score = tk.Entry(frame_model, width=10)
        self.entry_score.grid(row=2, column=1, padx=5, pady=5, sticky=tk.W)
        self.entry_score.insert(0, "0.5")  # 默认值

        self.btn_confirm = tk.Button(frame_model, text="确定", command=self._validate_input)
        self.btn_confirm.grid(row=2, column=2, padx=5, pady=5, sticky=tk.W)

        # 底部按钮
        # frame_button = tk.Frame(self.window, bd=2, relief=tk.GROOVE)
        # frame_button.pack(fill=tk.X, padx=10, pady=10)
        btn_container = tk.Frame(self.window)
        btn_container.pack(side=tk.TOP, pady=20)  # 垂直方向居中
        self.btn_start_collect = tk.Button(btn_container, text="开始", width=10, height=2,
                                           command=self._start_process)
        self.btn_start_collect.grid(row=3, column=0, pady=20, padx=30)

        self.btn_stop_collect = tk.Button(btn_container, text="结束", width=10, height=2,
                                          command=self._stop_process)
        self.btn_stop_collect.grid(row=3, column=1, pady=20, padx=30)
        self.btn_stop_collect.config(state="disabled")

    # 更新运行时长的函数
    def update_running_time(self):
        # 计算已运行秒数
        elapsed_seconds = int(time.time() - time.mktime(time.strptime(self.start_time, "%Y-%m-%d %H:%M:%S")))
        # 转换为时分秒格式
        hours, remainder = divmod(elapsed_seconds, 3600)
        minutes, seconds = divmod(remainder, 60)
        time_str = f"{hours:02d}:{minutes:02d}:{seconds:02d}"
        self.lbl_running_time.config(text=time_str)
        # 每秒更新一次
        self.window.after(1000, self.update_running_time)

    def _validate_input(self):
        """验证输入是否为0-1之间的浮点数"""
        input_str = self.entry_score.get().strip()
        try:
            number = float(input_str)
            if 0 <= number <= 1:
                self.score_threshold = number
                # messagebox.showinfo("提示", f"阈值已更新为: {number}")
            else:
                messagebox.showwarning("警告", "请输入0-1之间的数值！")
        except ValueError:
            messagebox.showwarning("警告", "请输入有效的数字！")

    def refresh_ports(self):
        """刷新可用串口列表"""
        ports = [port.device for port in self.serial_process.list_serial_port()]
        self.combo_water['values'] = ports
        self.combo_data['values'] = ports
        if ports:
            self.combo_water.current(0)
            self.combo_data.current(0)
        else:
            print("未检测到可用串口")

    def _connect_water_combo(self):
        """
        连接喂水串口
        :return:
        """
        self.pump_controller = WaterPumpController(port=self.combo_water.get())

    def _conncet_data_combo(self):
        """
        数据接收串口测试
        :return:
        """
        self.serial_process.open_serial_port(port=self.combo_data.get())
        self.serial_process.send_command(bytearray(frequency_cmd_500))  # 设置频率
        res1 = self.serial_process.read_data(240)
        self.serial_process.send_command(bytearray(channel_cmd_60))
        res = self.serial_process.read_data(240)
        print(len(res), res)
        if len(res1) == 240 and len(res) == 240:
            messagebox.showinfo("提示", "数据串口连接成功")
            return
        else:
            self.serial_process.close_serial_port()
            messagebox.showinfo("提示", "数据串口连接失败，请更换串口")
            return

    def get_threshold(self):
        """
        提供外部获取阈值的接口
        :return:
        """
        return self.score_threshold

    def _choose_model(self):
        """
        解码模型选择
        :return:
        """
        """打开文件选择对话框选择模型文件"""
        # 打开文件选择对话框，可过滤文件类型
        self.model_path = filedialog.askopenfilename(
            title="选择模型文件",
            filetypes=[
                ("模型文件", "*.h5 *.pkl *.pth *.pt *.model *.mat"),  # 常见模型文件格式
                ("所有文件", "*.*")
            ]
        )

        # 如果选择了文件，更新显示路径
        if self.model_path:
            self.model_path_var.set(self.model_path)

    def _load_model(self):

        is_mat = False

        if self.model_path_var.get().endswith(".mat"):
            is_mat = True
        print("模型路径:", self.model_path_var.get())
        self.decoder = MonkeyDecoder(
            model_path=self.model_path_var.get(),
            window_size=self.win_size,
            step_size=self.step,
            channel_num=self.channel_num,
            fs=self.fs,
            is_mat=is_mat
        )

    def _start_process(self):
        if self.pump_controller is None:
            # 显示警告提示框
            messagebox.showwarning("警告", "请连接喂水串口")
            return
        if self.decoder is None:
            # 显示警告提示框
            messagebox.showwarning("警告", "请先加载模型")
            return
        self.disable_config_controls()
        joystick_controller = JoystickController()
        self.decoder.start()  # 开始解码
        self.processor = SerialPacketProcessor(max_queue_size=1000, decoder=self.decoder, port_name="COM9",
                                               serial_processor=self.serial_process)
        self.processor.start()

        self.cursor_control = CursorControl(self.master, joystick_controller, self.pump_controller, self.decoder,
                                            self)
        # 判断串口是否正常
        self.window.after(1000, self._update_status)
        self.btn_start_collect.config(state="disabled")
        self.btn_stop_collect.config(state="normal")

    def _stop_process(self):
        if self.processor:
            self.processor.stop()
        if self.cursor_control:
            self.cursor_control.on_close()
        if self.decoder:
            self.decoder.stop()

    def update_trial(self, trial_result):
        """
        更新状态
        :param device_status:
        :param trial_result:
        :return:
        """
        self.trial_result_var.set(trial_result)

    def disable_config_controls(self):
        """
        禁用串口和模型配置控件
        :return:
        """
        self.combo_water.config(state="disabled")
        self.combo_data.config(state="disabled")
        self.btn_send_data.config(state="disabled")
        self.btn_send_water.config(state="disabled")
        self.btn_select_model.config(state="disabled")
        self.btn_load_model.config(state="disabled")
        self.btn_refresh.config(state="disabled")

    def _update_status(self):
        if self.processor:
            read_num = self.processor.get_read_num()
            if read_num > 130 * (self.fs - 40):  # 正常一秒钟是130*fs个字节，考虑到延迟等，允许漏40包，根据实际情况修改
                self.device_status_var.set("正常")
            else:
                self.device_status_var.set("异常")
                print("update_status 异常:", read_num)
            self.processor.set_read_num(0)
        self.master.after(1000, self._update_status)
